package com.hyh.user.util;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hyh.user.domain.RedisData;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Component
@Slf4j
public class CacheClient {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * redis的set方法是一个字符串的存储方法
     * @param key:redis当中的唯一key，value:存储的值 类型为Object，time:过期时间，unit:时间单位
     * @return
     */
    public void set(String key, Object value, Long time, TimeUnit unit){
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value),time,unit);
    }


  /**
   * @description 获取key
   * @param
   * @return
   * @author
   * @date  2024/4/15 22:47
   */
    public String get(String key){
        return stringRedisTemplate.opsForValue().get(key);
    }


    /**
     * redis的get方法是一个字符串的获取方法 加上设置逻辑过期时间
     * @param
     * @return
     */
    public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit){
        // 设置逻辑过期时间
        RedisData<Object> redisData = new RedisData<>();
        redisData.setData(value);
        redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
        // 写入redis当中
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
    }

    /*
     * 缓存击穿中的互斥锁 解决缓存穿透问题
     * @param
     * @return
     */

    public <T ,ID> T queryWithPassThrough(String keyPrefix, ID id, Class<T> type, Function<ID,T> dbFallBack,Long time, TimeUnit unit){
        String key = keyPrefix + id;
        log.info("key:{}",key);
        //1 先从缓存中获取数据
        String json = stringRedisTemplate.opsForValue().get(key);
        log.info("json:{}",json);
        // 判断缓存是否为null
        if(StrUtil.isNotBlank(json)){
            return JSONUtil.toBean(json,type);
        }
        // 判断命中的缓存是否是空值 null相当于""字符串
        if(json != null){
            // 返回一个错误消息
            return null;
        }
        // 查不到缓存的数据 查询数据库
        T t = dbFallBack.apply(id);
        log.info("t:{}",t);
        // 不存在 写入缓存为null
        if(t == null){
            this.set(key,"",time,unit);
            return null;
        }
        // 存在 写入缓存 返回值
        this.set(key,t,time,unit);
        return t;
    }
}
